<?php
/**
 * Doctrine bootstrap resource
 *
 * Used to integrate doctrine into zend framework. Supports multiple
 * connections, PDO options, and multiple model paths
 *
 * @author Matti Niemela <matti@mattiniemela.net>
 */
class WMC_Application_Resource_Doctrine extends Zend_Application_Resource_ResourceAbstract
{
	/**
	 * @var Doctrine_Manager
	 */
	protected $_manager = null;

	/**
	 * @see library/Zend/Application/Resource/Zend_Application_Resource_Resource#init()
	 * @return Doctrine_Manager
	 */
	public function init()
	{
		return $this->getManager();
	}

	/**
	 * Maps .ini settings from string to real constants.
	 *
	 * @param array $options
	 * @param string $constantClass Eg. PDO or Doctrine
	 * @return array
	 */
	protected function _mapOptionsToConstants(array $options = array(), $constantClass = 'PDO')
	{
		$return = array();

		// Iterate through different options
		foreach($options as $key => $option)
		{
			// If both key and value appears to be class constants
			if(
				is_array($option) === false
				&&	preg_match('@^'. $constantClass .'\:\:[A-Z0-9_]+$@u', $key) == 1
				&&	preg_match('@^'. $constantClass .'\:\:[A-Z0-9_]+$@u', $option) == 1
			)
			{
				$return[constant($key)] = constant($option);
				continue;
			}

			// If value appears to be a constant, but not the key
			if(
				is_array($option) === false
				&&	preg_match('@^'. $constantClass .'\:\:[A-Z0-9_]+$@u', $option) == 1
			)
			{
				$return[$key] = constant($option);
				continue;
			}

			// If only the key appears to be constant
			if(preg_match('@^'. $constantClass .'\:\:[A-Z0-9_]+$@u', $key) == 1)
			{
				$return[constant($key)] = $option;
				continue;
			}

			// No constants involved
			$return[$key] = $option;
		}

		return $return;
	}

	/**
	 * Initializes and returns doctrine manager.
	 *
	 * @return Doctrine_Manager
	 */
	public function getManager()
	{
		if(null === $this->_manager)
		{
			$options = $this->getOptions();

			// Set Doctrine class and model autoload
			require_once 'Doctrine.php';
			spl_autoload_register(array('Doctrine', 'autoload'));

			$manager = Doctrine_Manager::getInstance();

			// Check if there are any manager lever options
			if(array_key_exists('options', $options))
			{
				$managerOptions = $this -> _mapOptionsToConstants((array) $options['options'], 'Doctrine');
				foreach($managerOptions as $key => $value)
				{
					$manager -> setAttribute($key, $value);
				}
			}

			// Iteration per connection
			foreach($options['connections'] as $name => $connection)
			{
				$pdoOptions      = $this->_mapOptionsToConstants((array) $connection['options']['pdo'], 'PDO');
				$doctrineOptions = $this->_mapOptionsToConstants((array) $connection['options']['doctrine'], 'Doctrine');

				$db = new PDO($connection['dsn'], $connection['username'], $connection['password'], $pdoOptions);

				// Add attrs to PDO
				foreach ($pdoOptions as $key => $value)
				{
					$db->setAttribute($key, $value);
				}

				// Add PDO connection into manager
				$conn = Doctrine_Manager::connection($db, $name);
				$conn->setOption('username', $connection['username']);
				$conn->setOption('password', $connection['password']);

				// Add attrs to Doctrine
				foreach ($doctrineOptions as $key => $value)
				{
					$conn->setAttribute($key, $value);
				}
			}

			// Load models
			Doctrine::loadModels($options['models_path']);

			$this->_manager = $manager;
		}

		return $this->_manager;
	}
}
